﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
public class LoadManager : UnitySingleton<LoadManager>
{
    private List<IAssetLoader> assetLoaders;
    private Dictionary<string, IAssetBundle> dicAsseetBundles;
    private Dictionary<UInt32, string> dicPrefab;
    private Dictionary<UInt32, string> dicAsset;
    private Dictionary<string, List<Action<UInt32>>> dicPrefabCallBack;     //预设加载回调字典

    private Dictionary<string, ABInfo> dicABInfos;
    private Dictionary<uint, ABInfo> dicPrefabs;
    private Dictionary<string, Dictionary<string, List<ABInfo>>> dicDormancy; //待销毁资源
    private List<ABInfo> listDormancy;

    private UInt32 prefabResID;
    private UInt32 assetResID;

    private AssetBundleManifest manifest;

    private IAssetLoader edirotLoader;
    private IAssetLoader abLoader;

    private uint prefabID;

    private GameObject gameObjectPool;

    //private IAssetLoader webLoader;

    public override void Init()
    {
        assetLoaders = new List<IAssetLoader>();
        dicAsseetBundles = new Dictionary<string, IAssetBundle>();
        dicPrefab = new Dictionary<UInt32, string>();
        dicAsset = new Dictionary<UInt32, string>();
        dicABInfos = new Dictionary<string, ABInfo>();
        dicPrefabs = new Dictionary<uint, ABInfo>();
        dicDormancy = new Dictionary<string, Dictionary<string, List<ABInfo>>>();
        listDormancy = new List<ABInfo>();

        gameObjectPool = new GameObject("GameObjectPool");
        gameObjectPool.AddComponent<RectTransform>();
        gameObjectPool.transform.SetParent(this.gameObject.transform);
        DontDestroyOnLoad(gameObjectPool);
        gameObjectPool.SetActive(false);
        prefabResID = 0;
        assetResID = 0;
        prefabID = 0;
        //#if UNITY_EDITOR
        abLoader = new EditorAssetLoader();
        abLoader.Init();
        assetLoaders.Add(abLoader);
        //#endif
        //abLoader = new ABLoader();
        //abLoader.Init();
        //assetLoaders.Add(abLoader);
    }

    void Update()
    {
        if (assetLoaders != null)
        {
            //检测是否有资源需要加载
            for (int i = 0; i < assetLoaders.Count; i++)
            {
                assetLoaders[i].Load();
            }
        }
        if(listDormancy != null && listDormancy.Count > 0)
        {
            //检测资源是否要删除
            for (int i = 0; i < listDormancy.Count; i++)
            {
                ABInfo aBInfo = listDormancy[i];
                if(!aBInfo.isActivate && aBInfo.timeTick < GlobalApi.GetTimeTicks())
                {
                    OnObjDestroy(aBInfo);
                }
            }
        }

    }

    /// <summary>
    /// 加载预设资源
    /// </summary>
    /// <param name="bundleName"></param>
    /// <param name="assetName"></param>
    /// <param name="callback"></param>
    /// <returns></returns>
    public UInt32 LoadPrefab(string bundleName, string assetName, Action<UInt32, UInt32> callback = null)
    {

        prefabID++;
        ABInfo aBInfo = GetObj(bundleName, assetName);
        if(aBInfo != null)
        {
            GameObject go = InstantiatePrefab(aBInfo.objID);
            dicPrefabs.Add(prefabID, aBInfo);
            if (callback != null)
            {
                callback(prefabID, aBInfo.objID);
            }
        }
        else
        {
            if (dicABInfos.ContainsKey(bundleName))
            {
                //资源加载
                aBInfo = dicABInfos[bundleName];
                IAssetBundle assetBundle = aBInfo.assetBundle;
                //资源引用+1
                assetBundle.AddReferenceCount();

                ABInfo tempABInfo = new ABInfo();
                tempABInfo.bundName = bundleName;
                tempABInfo.assetName = assetName;
                tempABInfo.assetBundle = assetBundle;
                tempABInfo.handleKey = aBInfo.handleKey;
                tempABInfo.isActivate = true;
                GameObject obj = InstantiatePrefab(assetBundle, assetName);
                uint skinID = ObjectManager.Instance.AddObj(obj);
                tempABInfo.objID = skinID;
                dicPrefabs.Add(prefabID, tempABInfo);
                if (callback != null)
                {
                    callback(prefabID, skinID);
                }
            }
            else
            {
                //资源未加载
                abLoader.LoadPrefab(bundleName, assetName, (handleKey, assetBundle) =>
                {
                    aBInfo = new ABInfo();
                    aBInfo.bundName = bundleName;
                    aBInfo.isActivate = true;
                    aBInfo.handleKey = handleKey;
                    aBInfo.assetBundle = assetBundle;
                    aBInfo.assetName = assetName;
                    dicABInfos.Add(bundleName, aBInfo);
                    GameObject obj = InstantiatePrefab(assetBundle, assetName);
                    dicPrefabs.Add(prefabID, aBInfo);
                    uint skinID = ObjectManager.Instance.AddObj(obj);
                    aBInfo.objID = skinID;
                    if (callback != null)
                    {
                        callback(prefabID, skinID);
                    }
                });
            }
        }
        return prefabID;
    }

    /// <summary>
    /// 加载图集等资源
    /// </summary>
    /// <param name="bundleName"></param>
    /// <param name="assetName"></param>
    /// <param name="callback"></param>
    /// <returns></returns>
    public UInt32 LoadAsset(string bundleName, Action<UInt32> callback = null)
    {
        assetResID = abLoader.LoadAsset(bundleName, callback);
        return assetResID;
    }

    /// <summary>
    /// 卸载预设资源
    /// </summary>
    /// <param name="resID"></param>
    public void UnLoadPrefab(UInt32 resID)
    {
        if (dicPrefabs.ContainsKey(resID))
        {
            ABInfo aBInfo = dicPrefabs[resID];
            SetDormancy(aBInfo);
            dicPrefabs.Remove(resID);
        }

        //abLoader.UnLoadPrefab(resID);
    }

    /// <summary>
    /// 卸载图集等资源
    /// </summary>
    /// <param name="resID"></param>
    public void UnLoadAsset(UInt32 resID)
    {
        abLoader.UnLoadAsset(resID);
    }

    /// <summary>
    /// 卸载AB资源
    /// </summary>
    public void UnLoadAB(string bundleName)
    {
        abLoader.UnLoad(bundleName);
    }

    /// <summary>
    /// 获取AB资源
    /// </summary>
    /// <param name="resID"></param>
    /// <returns></returns>
    public AssetBundle GetAssetRes(UInt32 resID)
    {
        string bundleName = "";
        if (dicAsset.TryGetValue(resID, out bundleName))
        {
            IAssetBundle ab = null;
            if (dicAsseetBundles.TryGetValue(bundleName, out ab))
            {
                return ab.GetAssetBundle();
            }
        }
        return null;
    }

    public Sprite GetSpriteByResIDAndName(UInt32 resID, string spriteName)
    {
        return abLoader.GetSpriteByResIDAndName(resID, spriteName);
    }


    private GameObject InstantiatePrefab(IAssetBundle assetBundle, string assetName)
    {
        IAssetBundle abRes = assetBundle;
        GameObject obj = abRes.LoadRes<GameObject>(assetName);
        GameObject go1 = GameObject.Instantiate(obj);
        GameObject g = GameObject.Find("Canvas");
        go1.transform.SetParent(g.transform);
        return go1;
    }

    private GameObject InstantiatePrefab(uint skinID)
    {
        GameObject go1 = ObjectManager.Instance.GetGameObject(skinID);
        if(go1 != null)
        {
            GameObject g = GameObject.Find("Canvas");
            go1.transform.SetParent(g.transform);
            return go1;
        }
        return null;
    }

    private void SetDormancy(ABInfo aBInfo)
    {
        aBInfo.isActivate = false;
        aBInfo.timeTick = GlobalApi.GetTimeTicks() + 10;
        GameObject go = ObjectManager.Instance.GetGameObject(aBInfo.objID);
        if(go != null)
        {
            go.transform.SetParent(gameObjectPool.transform);
        }
        if(dicDormancy.ContainsKey(aBInfo.bundName))
        {
            Dictionary<string, List<ABInfo>> tempDic = dicDormancy[aBInfo.bundName];
            if(tempDic.ContainsKey(aBInfo.assetName))
            {
                tempDic[aBInfo.assetName].Add(aBInfo);
            }
            else
            {
                List<ABInfo> tempList = new List<ABInfo>();
                tempList.Add(aBInfo);
                tempDic.Add(aBInfo.assetName, tempList);
            }
        }
        else
        {
            Dictionary<string, List<ABInfo>> tempDic = new Dictionary<string, List<ABInfo>>();
            List<ABInfo> tempList = new List<ABInfo>();
            tempList.Add(aBInfo);
            tempDic.Add(aBInfo.assetName, tempList);
            dicDormancy.Add(aBInfo.bundName, tempDic);
        }
        listDormancy.Add(aBInfo);
    }

    private void OnObjDestroy(ABInfo aBInfo)
    {
        listDormancy.Remove(aBInfo);
        aBInfo.assetBundle.ReleaseRes();
        if (dicDormancy.ContainsKey(aBInfo.bundName))
        {
            Dictionary<string, List<ABInfo>> tempDic = dicDormancy[aBInfo.bundName];
            if (tempDic.ContainsKey(aBInfo.assetName))
            {
                List<ABInfo> list = tempDic[aBInfo.assetName];
                list.Remove(aBInfo);
                if(list.Count <= 0)
                {
                    tempDic.Remove(aBInfo.assetName);
                    if(tempDic.Count <= 0)
                    {
                        dicDormancy.Remove(aBInfo.bundName);
                    }
                }
            }
        }
        GameObject go = ObjectManager.Instance.GetGameObject(aBInfo.objID);
        Destroy(go);
        aBInfo = null;
    }

    private ABInfo GetObj(string bundleName,string assetName)
    {
        if (dicDormancy.ContainsKey(bundleName))
        {
            Dictionary<string, List<ABInfo>> tempDic = dicDormancy[bundleName];
            if (tempDic.ContainsKey(assetName))
            {
                List<ABInfo> list = tempDic[assetName];
                ABInfo aBInfo = list[0];
                aBInfo.isActivate = true;
                list.Remove(aBInfo);
                if (list.Count <= 0)
                {
                    tempDic.Remove(aBInfo.assetName);
                    if (tempDic.Count <= 0)
                    {
                        dicDormancy.Remove(aBInfo.bundName);
                    }
                }
                if(listDormancy.Contains(aBInfo))
                {
                    listDormancy.Remove(aBInfo);
                }
                return aBInfo;
            }
           
        }
        return null;
    }
}
